/*
 *  Copyright (C) 2010 Martin Haulrich <mwh.isv@cbs.dk> and Matthias Buch-Kromann <mbk.isv@cbs.dk>
 *
 *  This file is part of the IncrementalParser package.
 *
 *  The IncrementalParser program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.osdtsystem.incparser.main;


import java.util.ArrayList;
import java.util.List;
import org.osdtsystem.incparser.data.ConllIterator;
import org.osdtsystem.incparser.features.FeatureHandler;
import org.osdtsystem.incparser.features.FeatureHandlerMapBased;
import org.osdtsystem.incparser.learners.MIRALearner;
import org.osdtsystem.incparser.features.WeightVector;
import org.osdtsystem.incparser.logging.Log;
import org.osdtsystem.incparser.loss.LabelledLoss;
import org.osdtsystem.incparser.trainers.ConllTrainer;
import org.osdtsystem.incparser.loss.Loss;
import org.osdtsystem.incparser.parsers.Parser;
import org.osdtsystem.incparser.trainers.Trainer;
import org.osdtsystem.incparser.loss.UnlabelledLoss;
import org.osdtsystem.incparser.parsers.MstParserLabelled;
import org.osdtsystem.incparser.parsers.MstParserUnlabelled;

/**
 *
 * @author Martin Haulrich and Matthias Buch-Kromann
 */
public class MstUnlabelled {
    static final FeatureHandler types = new FeatureHandlerMapBased(false);
    static final FeatureHandler strings = new FeatureHandlerMapBased(true);
    static final FeatureHandler features = new FeatureHandlerMapBased(false);

    public static void main(String[] args) throws Exception {
        new MstUnlabelled().run(args);
    }
    
    Parser createParser1() {
        //return new MstParserLabelled(types, strings, features);
        return new MstParserUnlabelled(types, strings, features);
    }

    Parser createParser2(Parser parser1) {
        return parser1;
        //return new IncrementalMstParser(types, strings, features);
    }

    Loss createLoss() {
        return new UnlabelledLoss();
        //return new LabelledLoss();
    }

    Trainer createTrainer(Parser parser1, Parser parser2, Loss loss) {
        return(new ConllTrainer(
                new MIRALearner(100000), parser1, parser2, loss));
    }

    void run(String[] args) throws Exception {
        Options.parseArgs(args);
        Log.chandler.setLevel(Options.levelOption("train.loglevel.console"));
        Log.phandler.setLevel(Options.levelOption("train.loglevel.html"));

        // Start parser logging
        Log.phandler.openMain();

        // Print tester
        Log.config("Running ", this.getClass());

        // CONLL training and evaluation file names, and iterators
        String conllTrainingFilename = Options.option("train.file");
        String conllEvaluationFilename = Options.option("eval.file");
        ConllIterator trainIterator = new ConllIterator(conllTrainingFilename);

        // Create feature handler, scorer and parser
        Parser parser1 = createParser1();
        Parser parser2 = createParser2(parser1);
        Parser parser = parser1;

        // Create trainer and train weights
        Loss loss = createLoss();
        Trainer trainer = createTrainer(parser1, parser2, loss);
        WeightVector weightVector = trainer.train(trainIterator,
                    Options.intOption("train.iterations"),
                    Options.intOption("train.iterations1"));
        trainIterator.close();

        // Set up logging level and prepare for parsing
        Log.chandler.setLevel(Options.levelOption("parse.loglevel.console"));
        Log.phandler.setLevel(Options.levelOption("parse.loglevel.html"));
        List<String> evalFiles = new ArrayList<String>();
        List<Parser> evalParsers = new ArrayList<Parser>();
        if (Options.option("eval.output1") != null && parser1 != null) {
            evalParsers.add(parser1);
            evalFiles.add(Options.option("eval.output1"));
        }
        if (Options.option("eval.output2") != null && parser2 != null) {
            evalParsers.add(parser2);
            evalFiles.add(Options.option("eval.output2"));
        }

        // Parse the evaluation file with the requested parsers
        Log.info("Parsing...");
        for (int p = 0; p < evalParsers.size(); ++p) {
            // Find current parser and output file
            parser = evalParsers.get(p);
            String outputFile = evalFiles.get(p);
            Log.phandler.openIteration("Parse with " + parser.getClass());
            Log.config("Parser: ", parser.getClass());
            Log.pushStartTime();

            // Run current parser
            parser.parse(weightVector, conllEvaluationFilename, outputFile, loss);

            // Log parsing info
            Log.info("   finished parsing[" + (p + 1) + "]: " 
                    + " [" + Log.secondsElapsed() + " seconds,  "
                    + parser.totalLoss() / parser.wordCounter() + " avg.loss/word, "
                    + Log.memoryUsed() + " MB heap]");


            // Close iteration
            Log.phandler.closeIteration();
        }
        Log.phandler.closeMain();
    }
}
